﻿namespace CN2P.Tests
{
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Net;

    using Microsoft.VisualStudio.TestTools.UnitTesting;

    [TestClass]
    public class ProductServiceTest : BaseServiceTest
    {
        private const string ProductItem = @"{
            'prodId' : '191201',
            'tags' : [ 'TV', 'Electronics'],
            'brand' : 'Sony',
            'model' : 'Bravia',
            'desc' : 'LCD Flat Screen TV',
            'price' : 749.99,
            'serialNo' : 'sb129412305-2381',
            'size' : '52 inches',
            'manufDate' : '2013-01-24',
            'weight' : '47 lbs',
            'shipWeight' : '64.56 lbs',
            'imageUrl': '/productimages/101.png'
        }";

        [TestMethod]
        public void productCreateWalkthroughTest()
        {
            var prod = this.CreateRandomProduct();
            try
            {
                var model = this.Service.ProductsService.GetProduct(prod.ProdId);
                Assert.AreEqual(prod.ProdId, model.prodId);
            }
            catch (Exception)
            {
                throw new Exception("Couldn't get product short info");
            }
            try
            {
                var model = this.Service.ProductsService.GetProductDetails(prod.ProdId);
                Assert.AreEqual(prod.ProdId, model.ProdId);
            }
            catch (Exception)
            {
                throw new Exception("Couldn't get product details");
            }
        }

        [TestMethod]
        public void productExtraPropertiesTest()
        {
            var prod = new FullProductModelExt
            {
                Tags = new List<string>() { "tag1", "tag2" },
                ProdName = Guid.NewGuid().ToString(),
                ProdDesc = Guid.NewGuid().ToString(),
                ImageUrl = Guid.NewGuid().ToString(),
                ProdPrice = 1,
                MyProp = Guid.NewGuid().ToString(),
            };
            var prodId = this.Service.ProductsService.CreateProduct(prod);
            var res = this.Service.ProductsService.GetProductDetails(prodId, props => new FullProductModelExt(props));
            Assert.AreEqual(prod.MyProp, res.MyProp);
        }

        //[TestMethod]
        //public void productGetProductsTest()
        //{
        //    this.Service.ProductsService.DeleteAll();
        //    var ids = new List<string>();
        //    for (var i = 0; i < 15; i++)
        //    {
        //        var prod = this.CreateRandomProduct();
        //        ids.Add(prod.ProdId);
        //    }

        //    var firstPage = this.Service.ProductsService.Get(1, 10);
        //    var secondPage = this.Service.ProductsService.Get(2, 10);
        //    var thirdPage = this.Service.ProductsService.Get(3, 10);

        //    Assert.AreEqual(15, firstPage.TotalCount);
        //    Assert.AreEqual(15, secondPage.TotalCount);
        //    Assert.AreEqual(15, thirdPage.TotalCount);

        //    Assert.AreEqual(10, firstPage.Products.Count);
        //    Assert.AreEqual(5, secondPage.Products.Count);
        //    Assert.AreEqual(0, thirdPage.Products.Count);

        //    var all = firstPage.Products.Union(secondPage.Products).ToList();
        //    for (var i = 0; i < 15; i++)
        //    {
        //        var prodId = ids[i];
        //        Assert.AreEqual(1, all.Count(item => item.prodId == prodId));
        //    }
        //}

        [TestMethod]
        public void productGetProductDetailsByIdTest()
        {
            this.Service.ProductsService.DeleteAll();

            var ids = new List<string>();
            for (var i = 0; i < 15; i++)
            {
                var prod = GetRandomProduct();
                prod.Brand = "Sony";
                prod.ProdPrice = 749.99m;
                ids.Add(this.Service.ProductsService.CreateProduct(prod));
            }

            var prodId = ids[5];
            var model = this.Service.ProductsService.GetProductDetails(prodId);
            Assert.AreEqual(prodId, model.ProdId, "Check that we got needed product");
            Assert.AreEqual("Sony", model.Brand);
            Assert.AreEqual(749.99m, model.ProdPrice);
        }

        [TestMethod]
        public void productGetProductShortInfoByIdTest()
        {
            this.Service.ProductsService.DeleteAll();

            var ids = new List<string>();
            for (var i = 0; i < 15; i++)
            {
                var prod = GetRandomProduct();
                prod.Brand = "Sony";
                prod.ProdPrice = 749.99m;
                ids.Add(this.Service.ProductsService.CreateProduct(prod));
            }

            var prodId = ids[5];
            var model = this.Service.ProductsService.GetProductDetails(prodId);
            Assert.AreEqual(prodId, model.ProdId, "Check that we got needed product");
            Assert.AreEqual("Sony", model.Brand);
            Assert.AreEqual(749.99m, model.ProdPrice);
        }

        [TestMethod]
        public void productGetMissingProductByIdTest()
        {
            this.Service.ProductsService.DeleteAll();

            var model = this.Service.ProductsService.GetProductRaw("10010");
            Assert.AreEqual(HttpStatusCode.NotFound, model.Code);
        }

        [TestMethod]
        public void productCreateJsonTest()
        {
            var prodId = this.Service.ProductsService.CreateProduct(ProductItem);
            var model = this.Service.ProductsService.GetProductDetails(prodId);
            Assert.AreEqual(model.Brand, "Sony");
        }

        //[TestMethod]
        //public void productUpdateTest()
        //{
        //    var original = this.CreateRandomProduct();

        //    var updated = GetRandomProduct();
        //    updated.ProdId = original.ProdId;

        //    this.Service.ProductsService.UpdateProduct(original.ProdId, updated);

        //    var model = this.Service.ProductsService.GetProductDetails(original.ProdId);
        //    Assert.AreEqual(original.ProdId, model.ProdId);
        //    Assert.AreEqual(updated.ProdName, model.ProdName);
        //    Assert.AreEqual(updated.ProdDesc, model.ProdDesc);
        //    Assert.AreEqual(updated.ManufDate, model.ManufDate);
        //}

        //[TestMethod]
        //public void productDeleteTest()
        //{
        //    var prod = this.CreateRandomProduct();
        //    this.Service.ProductsService.DeleteProduct(prod.ProdId);
        //    var model = this.Service.ProductsService.GetProductRaw(prod.ProdId);
        //    Assert.AreEqual(HttpStatusCode.NotFound, model.Code);
        //}

        //[TestMethod]
        //public void productDeleteAllTest()
        //{
        //    for (var i = 0; i < 10; i++)
        //    {
        //        this.CreateRandomProduct();
        //    }

        //    this.Service.ProductsService.DeleteAll();
        //    var prods = this.Service.ProductsService.Get(1, 10);
        //    Assert.AreEqual(0, prods.TotalCount);
        //    Assert.AreEqual(0, prods.Products.Count);
        //}

        [TestMethod]
        public void productGetByNameTest()
        {
            for (var i = 0; i < 10; i++)
            {
                var prod = GetRandomProduct();
                prod.ProdName = "SearchByName_" + prod.ProdName;
                this.Service.ProductsService.CreateProduct(prod);
            }

            var model = this.Service.ProductsService.GetByName("SearchByName_");
            Assert.IsTrue(model.TotalCount >= 10);
            foreach (var prod in model.Products)
            {
                Assert.IsTrue(prod.prodName.StartsWith("SearchByName_"));
            }
        }

        [TestMethod]
        public void productGetByTagTest()
        {
            this.Service.ProductsService.DeleteAll();
            for (var i = 0; i < 10; i++)
            {
                var prod = GetRandomProduct();
                prod.ProdName = "SearchByTag_" + prod.ProdName;
                prod.Tags = new List<string>();
                prod.Tags.Add("tag_" + (i % 3).ToString());
                prod.Tags.Add(Guid.NewGuid().ToString());
                this.Service.ProductsService.CreateProduct(prod);
            }

            var model = Service.ProductsService.GetByTag("tag_2");
            Assert.IsTrue(model.TotalCount == 3);
            foreach (var prod in model.Products)
            {
                Assert.IsTrue(prod.prodName.StartsWith("SearchByTag_"));
                Assert.AreEqual(2, prod.tags.Count);
                Assert.IsTrue(prod.tags.Contains("tag_2"));
            }
        }

        [TestMethod]
        public void productGetProductTagsTest()
        {
            this.Service.ProductsService.DeleteAll();
            for (var i = 0; i < 10; i++)
            {
                var prod = GetRandomProduct();
                prod.ProdName = "SearchByTag_" + prod.ProdName;
                prod.Tags = new List<string> {"tag_" + (i%3).ToString()};
                this.Service.ProductsService.CreateProduct(prod);
            }

            var model = this.Service.ProductsService.GetTags();
            model = model.OrderBy(item => item).ToList();
            Assert.AreEqual(3, model.Count);
            Assert.AreEqual("tag_0", model[0]);
            Assert.AreEqual("tag_1", model[1]);
            Assert.AreEqual("tag_2", model[2]);
        }

        [TestMethod]
        public void productGetByIdTest()
        {
            this.Service.ProductsService.DeleteAll();

            var ids = new List<string>();
            for (var i = 0; i < 15; i++)
            {
                var prod = GetRandomProduct();
                prod.Brand = "CloudNinja";
                prod.ProdPrice = 99999999.99m;
                ids.Add(this.Service.ProductsService.CreateProduct(prod));
            }

            var idSet1 = ids.GetRange(4, 5).ToArray();

            var model = this.Service.ProductsService.GetByIds(idSet1);
            Assert.AreEqual(idSet1.Length, model.Products.Count, "Check to see that we returned same number of products requested");
            Assert.AreEqual(model.Products.Select(prod => prod.prodId).ToArray().Intersect(ids).Count(), idSet1.Length);
        }
    }
}
